#pragma once
#include <iostream>
#include <queue>
#include <pthread.h>

template<class T>
class BlockQueuePC // 基于阻塞队列的生产者消费者模型
{
public:
    BlockQueuePC(int cap)
    :_cap(cap)
    {
        pthread_mutex_init(&_mtx, nullptr);
        pthread_cond_init(&_consumer, nullptr);
        pthread_cond_init(&_producer, nullptr);
    }

    ~BlockQueuePC()
    {
        pthread_mutex_destroy(&_mtx);
        pthread_cond_destroy(&_consumer);
        pthread_cond_destroy(&_producer);
    }

public:
    void Push(T& task)
    {
        pthread_mutex_lock(&_mtx); // 申请锁
        while(_q.size() == _cap)
        {
            pthread_cond_wait(&_producer, &_mtx); // 释放锁，等待唤醒，唤醒后申请锁
        }
        _q.push(task);
        pthread_mutex_unlock(&_mtx); // 释放锁
        pthread_cond_signal(&_consumer); // 唤醒消费者
    }

    void Pop(T* task)
    {
        pthread_mutex_lock(&_mtx); // 申请锁
        while(_q.size() == 0)
        {
            pthread_cond_wait(&_consumer, &_mtx); // 释放锁，等待唤醒，唤醒后申请锁
        }
        *task = _q.front();
        _q.pop();
        pthread_mutex_unlock(&_mtx); // 释放锁
        pthread_cond_signal(&_producer); // 唤醒生产者
    }

private:
    int _cap; // 队列容量
    pthread_mutex_t _mtx; // 队列互斥锁
    std::queue<T> _q; // 队列
    pthread_cond_t _consumer; // 消费者条件变量
    pthread_cond_t _producer; // 生产者条件变量
};